using System;
using System.Diagnostics.Contracts;
using NHibernate;
using NHibernate.Cfg;
using System.Diagnostics;

namespace DataStore
{
    [ContractClass(typeof(IDatabaseContract))]
    public interface IDatabase
    {
        /// <summary>
        /// Gets or sets the path to the bookshelf.
        /// </summary>
        /// <value>The path.</value>
        string Path { get; set; }

        /// <summary>
        /// Gets the path to the empty database.
        /// </summary>
        /// <value>The empty database path.</value>
        string EmptyDatabasePath { get; }

        /// <summary>
        /// Resets this instance.
        /// </summary>
        void Reset();

        /// <summary>
        /// Creates a new application settings factory if not created previously.
        /// Singleton functionality.
        /// </summary>
        /// <param name="reinit">if set to <c>true</c> [reinit].</param>
        /// <returns></returns>
        ISessionFactory AppSettingsFactory(bool reinit);

        /// <summary>
        /// Creates a new application settings factory if not created previously.
        /// Singleton functionality.
        /// </summary>
        /// <returns></returns>
        ISessionFactory AppSettingsFactory();

        string ApplicationSettingsPath { get;  }

        /// <summary>
        /// Creates a new bookshelf factory if not created previously.
        /// Singleton functionality.
        /// </summary>
        /// <param name="path">The path to the bookshelf.</param>
        /// <param name="reinit">if set to <c>true</c> [reinit].</param>
        /// <returns></returns>
        ISessionFactory BookshelfFactory(string path, bool reinit);

        /// <summary>
        /// Creates a new bookshelf factory if not created previously.
        /// Singleton functionality.
        /// </summary>
        /// <param name="path">The path to the bookshelf.</param>
        /// <returns></returns>
        ISessionFactory BookshelfFactory(string path);

        /// <summary>
        /// Creates a new bookshelf factory if not created previously.
        /// Singleton functionality.
        /// </summary>
        /// <returns></returns>
        ISessionFactory BookshelfFactory();

        /// <summary>
        /// Opens the bookshelf.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="reinit">if set to <c>true</c> [reinit].</param>
        /// <returns></returns>
        void OpenBookshelf(string path, bool reinit);

        /// <summary>
        /// Opens the bookshelf.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <returns></returns>
        void OpenBookshelf(string path);

        /// <summary>
        /// Opens the bookshelf.
        /// </summary>
        /// <returns></returns>
        void OpenBookshelf();

        /// <summary>
        /// Opens the appllication settings.
        /// </summary>
        /// <param name="reinit">if set to <c>true</c> [reinit].</param>
        /// <returns></returns>
        ISession OpenAppSettings(bool reinit);

        /// <summary>
        /// Opens the appllication settings.
        /// </summary>
        /// <returns></returns>
        ISession OpenAppSettings();

        /// <summary>
        /// Gets the application settings path.
        /// </summary>
        /// <param name="applicationDataPath">The application data path.</param>
        /// <returns></returns>
        string GetApplicationSettingsPath();

        /// <summary>
        /// Gets the application configuration.
        /// </summary>
        /// <param name="applicationDataPath">The application data path.</param>
        /// <returns></returns>
        Configuration GetApplicationConfiguration(string applicationDataPath);

        /// <summary>
        /// Gets the application data path.
        /// </summary>
        /// <returns></returns>
        string GetApplicationDataPath();

        void ExportSchema(Configuration configuration, ISession session);

        void ChangeDatabase(string path);
        void ChangeDatabase(string path, bool reinit);
        /// <summary>
        /// Creates a unit of work
        /// </summary>
        /// <returns>A unit of work</returns>
        UnitOfWork CreateUnitOfWork();

        void GenerateEmptyDatabase();
        void CreateEmptyDatabase();
    }

    [ContractClassFor(typeof(IDatabase)), 
    DebuggerStepThrough]
    sealed class IDatabaseContract : IDatabase
    {

        #region IDatabase Members

        string IDatabase.Path
        {
            get
            {
                throw new System.NotImplementedException();
            }
            set
            {
                throw new System.NotImplementedException();
            }
        }

        /// <summary>
        /// Gets the path to the empty database.
        /// </summary>
        /// <value>The empty database path.</value>
        public string EmptyDatabasePath
        {
            get { throw new NotImplementedException(); }
        }

        void IDatabase.Reset()
        {
            throw new System.NotImplementedException();
        }

        ISessionFactory IDatabase.AppSettingsFactory(bool reinit)
        {
            throw new System.NotImplementedException();
        }

        ISessionFactory IDatabase.AppSettingsFactory()
        {
            throw new System.NotImplementedException();
        }

        ISessionFactory IDatabase.BookshelfFactory(string path, bool reinit)
        {
            Contract.Requires(!string.IsNullOrEmpty(path));
            Contract.Requires(!string.IsNullOrEmpty(System.IO.Path.GetFileName(path)) || path == ":memory:");

            return default(ISessionFactory);
        }

        ISessionFactory IDatabase.BookshelfFactory(string path)
        {
            Contract.Requires(!string.IsNullOrEmpty(path));
            Contract.Requires(!string.IsNullOrEmpty(System.IO.Path.GetFileName(path)) || path == ":memory:");

            return default(ISessionFactory);
        }

        ISessionFactory IDatabase.BookshelfFactory()
        {
            IDatabase @this = this;

            Contract.Requires(!string.IsNullOrEmpty(@this.Path));
            Contract.Requires(@this.Path == ":memory:" || !string.IsNullOrEmpty(System.IO.Path.GetFileName(@this.Path)));

            return default(ISessionFactory);
        }

        void IDatabase.OpenBookshelf(string path, bool reinit)
        {
            Contract.Requires(!string.IsNullOrEmpty(path));
            Contract.Requires(!string.IsNullOrEmpty(System.IO.Path.GetFileName(path)) || path == ":memory:");
        }

        void IDatabase.OpenBookshelf(string path)
        {

            Contract.Requires(!string.IsNullOrEmpty(path));
            Contract.Requires(!string.IsNullOrEmpty(System.IO.Path.GetFileName(path)) || path == ":memory:");
        }

        void IDatabase.OpenBookshelf()
        {
            IDatabase @this = this;

            Contract.Requires(!string.IsNullOrEmpty(@this.Path));
            Contract.Requires(@this.Path == ":memory:" || !string.IsNullOrEmpty(System.IO.Path.GetFileName(@this.Path)));
        }

        ISession IDatabase.OpenAppSettings(bool reinit)
        {
            throw new System.NotImplementedException();
        }

        ISession IDatabase.OpenAppSettings()
        {
            throw new System.NotImplementedException();
        }

        string IDatabase.GetApplicationSettingsPath()
        {
            throw new System.NotImplementedException();
        }

        Configuration IDatabase.GetApplicationConfiguration(string applicationDataPath)
        {
            Contract.Requires(!string.IsNullOrEmpty(applicationDataPath));

            return default(Configuration);
        }

        string IDatabase.GetApplicationDataPath()
        {
            throw new System.NotImplementedException();
        }


        public string ApplicationSettingsPath
        {
            get { throw new System.NotImplementedException(); }
        }

        public void ExportSchema(Configuration configuration, ISession session)
        {
            Contract.Requires(configuration != null);
            Contract.Requires(session != null);
            Contract.Requires(session.IsOpen);
            Contract.Requires(session.IsConnected);
        }

        public void ChangeDatabase(string path)
        {
            Contract.Ensures(!string.IsNullOrEmpty(path));
        }

        public void ChangeDatabase(string path, bool reinit)
        {
            Contract.Ensures(!string.IsNullOrEmpty(path));
        }

        public UnitOfWork CreateUnitOfWork()
        {
            IDatabase @this = this;

            Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(@this.Path), "Database path is null");

            Contract.Ensures(Contract.Result<UnitOfWork>().Session != null);
            Contract.Ensures(Contract.Result<UnitOfWork>().Session.IsOpen);
            Contract.Ensures(Contract.Result<UnitOfWork>().Session.IsConnected);
            

            return default(UnitOfWork);
        }

        public void GenerateEmptyDatabase()
        {
            throw new NotImplementedException();
        }

        public void CreateEmptyDatabase()
        {
            IDatabase @this = this;

            Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(@this.Path), "Database path is null");
        }

        #endregion
    }
}